#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/poll.h>

#define BUFFER_SIZE 1024

struct gpio_key{
    int gpio;   /* 记录gpio号 */
    struct gpio_desc *gpiod;     /* gpio描述符 */
    int flag;
    int irq;
};

static struct gpio_key *xxh_gpio_keys;

static int major = 0;       /* 确定主设备号         */
static struct class *key_class;
static struct fasync_struct *button_async;


/* 环形缓冲区 */
static int g_keys[BUFFER_SIZE];
static int r, w;

#define NEXT_POS(x) ((x+1) % BUFFER_SIZE)

static int is_key_buf_empty(void)
{
    return (r == w);
}

static int is_key_buf_full(void)
{
    return (r == NEXT_POS(w));
}

static void put_key(int key)
{
    if (!is_key_buf_full())
    {
        g_keys[w] = key;
        w = NEXT_POS(w);
    }
}

static int get_key(void)
{
    int key = 0;
    if (!is_key_buf_empty())
    {
        key = g_keys[r];
        r = NEXT_POS(r);
    }
    return key;
}

static DECLARE_WAIT_QUEUE_HEAD(key_waitqueue);  //wait queue定义

static int gpio_key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    int err, len;
    int key;

    if(is_key_buf_empty() && (file->f_flags & O_NONBLOCK))
        return -EAGAIN; // 非阻塞方式

    wait_event_interruptible(key_waitqueue, !is_key_buf_empty());
    key = get_key();
    err = copy_to_user(buf, &key, 4);
    len = 4;
    
    return len;
}

static unsigned int gpio_key_drv_poll(struct file *filep, struct poll_table_struct *wait)
{
    unsigned int events = 0;

    poll_wait(filep, &key_waitqueue, wait);

    return is_key_buf_empty()? 0 : POLLIN | POLLRDNORM;
}

static int gpio_key_drv_fasync(int fd, struct file *filp, int mode)
{
    if (fasync_helper(fd, filp, mode, &button_async) >= 0)
		return 0;
	else
		return -EIO;
}


/* 按键读取驱动 file_operations */
static struct file_operations xxh_key_drv = {
    .owner = THIS_MODULE,
    .read  = gpio_key_drv_read,
    .poll  = gpio_key_drv_poll,
    .fasync= gpio_key_drv_fasync,
};

/* 中断服务函数 */
static irqreturn_t xxh_gpio_key_isr(int irq, void *dev_id)
{
    struct gpio_key *gpio_key = dev_id;
    int val, key;

    val = gpiod_get_value(gpio_key->gpiod);
    printk("%s %s: key %d, key val %d\n", __FUNCTION__, __LINE__, gpio_key->gpio, val);
    key = (gpio_key->gpio << 8) | val;
    // 写入ringbuffer
    put_key(key);
    /* 唤醒队列 */
    wake_up_interruptible(&key_waitqueue);
    kill_fasync(&button_async, SIGIO, POLLIN);
    
    return IRQ_HANDLED;
}


/*
 * 4、从platform device获取GPIO
 *    把file_operations结构体告诉内核：注册驱动程序
 */
static int xxh_gpio_key_probe(struct platform_device *dev)
{
    int err, index;
    int count;
    struct device_node *np;
    enum of_gpio_flags flags;
    unsigned l_flags = GPIOF_IN;
    
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

    /* 设备节点获取 */
    np = dev->dev.of_node;
    
    /* 4.1 从设备树获取gpios属性 */
    count  = of_gpio_count(np);
    printk("The number of gpios is %d\n", count);

    xxh_gpio_keys = kzalloc(sizeof(struct gpio_key)*count, GFP_KERNEL);
    if(xxh_gpio_keys == NULL)
        return -1;

    for(index=0; index<count; index++) {
        /* 获取gpio号, 转化gpio描述符为一个整数值(未来可能会消失)
        desc->gdev->base + (desc - &desc->gdev->descs[0]);
        */
        xxh_gpio_keys[index].gpio = of_get_gpio_flags(np, index, &flags);
        printk("get flags: %#x \n", flags);
        
        /* 获取gpio描述符 */
        xxh_gpio_keys[index].gpiod = gpio_to_desc(xxh_gpio_keys[index].gpio);
        xxh_gpio_keys[index].flag = flags & OF_GPIO_ACTIVE_LOW;
        #if 0
        if(flags & OF_GPIO_ACTIVE_LOW) {
            printk("Set flags is GPIOF_ACTIVE_LOW.\n");
            l_flags |= GPIOF_ACTIVE_LOW;
        }
        err = devm_gpio_request_one(&dev->dev, xxh_gpio_keys[index].gpio, l_flags, NULL);
        #endif
        /* 获取GPIO中断号 */
        xxh_gpio_keys[index].irq = gpio_to_irq(xxh_gpio_keys[index].gpio);
        if (xxh_gpio_keys[index].irq < 0) {
            err = xxh_gpio_keys[index].irq;
            dev_err(&dev->dev,
                "Unable to get irq number for GPIO %d, error %d\n",
                xxh_gpio_keys[index].gpio, err);
            return err;
        }
        else {
            printk("%s %s line %d: get irq number is %d\n", __FILE__, __FUNCTION__, __LINE__, xxh_gpio_keys[index].irq);
        }
        /* 申请中断 */
        err = request_irq(xxh_gpio_keys[index].irq, xxh_gpio_key_isr, 
                          IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, 
                          "xxh_gpio_key", &xxh_gpio_keys[index]);
    }

    /* 注册file_operations结构体 */
    major = register_chrdev(0, "xxh_key", &xxh_key_drv);
    key_class = class_create(THIS_MODULE, "xxhkey");  /* /sys/class/xxhkey */
    err = PTR_ERR(key_class);
    if (IS_ERR(key_class)) {
        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
        unregister_chrdev(major, "led");
        return -1;
    }

    device_create(key_class, NULL, MKDEV(major, 0), NULL, "xxhkey"); /* /dev/xxhkey */

    return 0;
}

static int xxh_gpio_key_remove(struct platform_device *dev)
{
    struct device_node *np;
    int index, count;
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    device_destroy(key_class, MKDEV(major, 0));
    class_destroy(key_class);
    unregister_chrdev(major, "xxh_key");

    /* 设备节点获取 */
    np = dev->dev.of_node;
    count = of_gpio_count(np);
    for(index = 0; index < count; index++){
        free_irq(xxh_gpio_keys[index].irq, &xxh_gpio_keys[index]);
    }

    kfree(xxh_gpio_keys);
    return 0;
}


static const struct of_device_id gpio_key_xxh[] = {
    {.compatible = "xxh,gpio_key_drv"},
    {},
};

/* 1、定义platform_drver结构体 */
static struct platform_driver xxh_gpio_key_driver = {
    .probe  = xxh_gpio_key_probe,
    .remove = xxh_gpio_key_remove,
    .driver = {
        .name   = "xxh_gpio_key",
        .of_match_table = gpio_key_xxh,
    },
};

/* 2、入口函数：注册platform_driver结构体 */
static int __init gpio_key_init(void)
{
    int err;
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    err = platform_driver_register(&xxh_gpio_key_driver);

    return err;
}


/* 3、 有入口函数就应该有出口函数：卸载驱动程序时，就会去调用这个出口函数           */
static void __exit gpio_key_exit(void)
{
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    platform_driver_unregister(&xxh_gpio_key_driver);
}


/* 7. 其他完善：提供设备信息，自动创建设备节点                                     */

module_init(gpio_key_init);
module_exit(gpio_key_exit);

MODULE_LICENSE("GPL");

